﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Zen4SyncModel.Exceptions;
using System.Data.Objects;

namespace Zen4SyncModel
{
    internal class EntityProvider : IEntityProvider
    {

        /// <summary>
        /// Returns a new context of the Zen4SyncRepository.
        /// This method is used to create a new context every time that the Model wants to access the data base.
        /// In theory the interest of using this method is that it could be changed easily in a singleton if needed in the future.
        /// In practice using the "using" statement every time we call this method disposes the instance créated. To have a singleton instance,
        /// the "using" statement should be placed only in this method and be deleted from the other methods where this method is called.
        /// </summary>
        /// <returns>Returns a new context of the Zen4SyncRepository</returns>
        private static Zen4SyncRepositoryEntities GetContext()
        {
            return new Zen4SyncRepositoryEntities();
        }
        // TODO: Delete GetTestSessionDetails in EntityProvider, IEntityProvider.
        /// <summary>
        /// Returns all the clientSession entities of a testSession running on a testServer.
        /// </summary>
        /// <param name="testSessionId">Unique identifier of the Zen4Sync testSession.</param>
        /// <param name="testServerId">Unique identifier of the Zen4Sync testServer.</param>
        /// <returns>All the clientSession entities of a testSession running on a testServer.</returns>
        public List<clientSession> GetTestSessionDetails( Guid testSessionId, Guid testServerId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                List<clientSession> z4sClientSessions = z4sEntities.clientSession.Include( "testScenario" ).Include( "testScenario.activity" ).Include( "activityContext" ).Where(
                    c => c.clientSession_testServerId == testServerId
                    && c.clientSession_testSessionId == testSessionId ).ToList();
                return z4sClientSessions;
            }
        }

        /// <summary>
        /// Returns a syncSession entity from a givent syncSession id
        /// </summary>
        /// <param name="syncSessionId">Unique identifier of a Zen4Sync syncSession</param>
        /// <returns>A syncSession entity</returns>
        public syncSession GetSyncSession( Guid syncSessionId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                syncSession z4sSyncSession = z4sEntities.syncSession.Include( "distributor" ).Include( "publisher" ).Include( "internet" ).Where(
                    s => s.syncSession_id == syncSessionId ).SingleOrDefault();

                if ( z4sSyncSession == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Sync Session", syncSessionId.ToString() } );
                }
                return z4sSyncSession;
            }
        }

        /// <summary>
        /// Returns a sqlServerExecution entity from a given sqlServerExcecution id
        /// </summary>
        /// <param name="sqlServerExecutionId">Unique identifier of a Zen4Sync sqlServerExecution</param>
        /// <returns>A sqlServerExecution entity</returns>
        public sqlServerExecution GetSqlServerExecution( Guid sqlServerExecutionId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlServerExecution z4sSqlServerExecution = z4sEntities.sqlServerExecution.Where(
                    s => s.sqlServerExecution_id == sqlServerExecutionId ).SingleOrDefault();

                if ( z4sSqlServerExecution == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Sql Server Execution", sqlServerExecutionId.ToString() } );
                }
                return z4sSqlServerExecution;
            }
        }

        /// <summary>
        /// Returns a sqlServerCheckData entity from a given sqlServerExecution id
        /// </summary>
        /// <param name="sqlServerCheckDataId">Unique identifier of a Zen4Sync sqlServerCheckData</param>
        /// <returns>A sqlServerCheckData entity</returns>
        public sqlServerCheckData GetSqlServerCheckData( Guid sqlServerCheckDataId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlServerCheckData z4sSqlServerCheckData = z4sEntities.sqlServerCheckData.Where(
                    s => s.sqlServerCheckData_id == sqlServerCheckDataId ).SingleOrDefault();

                if ( z4sSqlServerCheckData == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Sql Server Check Data", sqlServerCheckDataId.ToString() } );
                }
                return z4sSqlServerCheckData;
            }
        }

        /// <summary>
        /// Returns a sqlceExecution entity from a given sqlceExecution id
        /// </summary>
        /// <param name="sqlceExecutionId">Unique identifier of a Zen4Sync sqlceExecution</param>
        /// <returns>A sqlceExecution entity</returns>
        public sqlceExecution GetSqlceExecution( Guid sqlceExecutionId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlceExecution z4sSqlceExecution = z4sEntities.sqlceExecution.Where(
                    s => s.sqlceExecution_id == sqlceExecutionId ).SingleOrDefault();

                if ( z4sSqlceExecution == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Sql CE Execution", sqlceExecutionId.ToString() } );
                }
                return z4sSqlceExecution;
            }
        }

        /// <summary>
        /// Returns a sqlceCheckData entity from a given sqlceCheckData id
        /// </summary>
        /// <param name="sqlceCheckDataId">Unique identifier of a Zen4Sync sqlceCheckData</param>
        /// <returns>A sqlceCheckData entity</returns>
        public sqlceCheckData GetSqlceCheckData( Guid sqlceCheckDataId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlceCheckData z4sSqlceCheckData = z4sEntities.sqlceCheckData.Where(
                    s => s.sqlceCheckData_id == sqlceCheckDataId ).SingleOrDefault();

                if ( z4sSqlceCheckData == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Sql CE Check Data", sqlceCheckDataId.ToString() } );
                }
                return z4sSqlceCheckData;
            }
        }

        /// <summary>
        /// Returns a sqlceBackup entity from a given sqlceBackup id
        /// </summary>
        /// <param name="sqlceBackupId">Unique identifier of a Zen4Sync sqlceBackup</param>
        /// <returns>A sqlceBackup entity</returns>
        public sqlceBackup GetSqlceBackup( Guid sqlceBackupId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlceBackup z4sSqlceBackup = z4sEntities.sqlceBackup.Where(
                    s => s.sqlceBackup_id == sqlceBackupId ).SingleOrDefault();

                if ( z4sSqlceBackup == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "SQL CE Backup", sqlceBackupId.ToString() } );
                }
                return z4sSqlceBackup;
            }
        }

        /// <summary>
        /// Returns a mefExecution entity from a given mefExecution id
        /// </summary>
        /// <param name="mefExecutionId">Unique identifier of a Zen4Sync mefExecution</param>
        /// <returns>A mefExecution entity</returns>
        public mefExecution GetMefExecution( Guid mefExecutionId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                mefExecution z4sMefExecution = z4sEntities.mefExecution.Include("mefComponentVersion").Where(
                    m => m.mefExecution_id == mefExecutionId ).SingleOrDefault();

                if ( z4sMefExecution == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Mef Execution", mefExecutionId.ToString() } );
                }
                return z4sMefExecution;
            }
        }

        /// <summary>
        /// Returns an activity entity from a given activity id
        /// </summary>
        /// <param name="activityId">Unique identifier of a Zen4Sync activity</param>
        /// <returns>An activity entity</returns>
        public activity GetActivity( Guid activityId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                activity z4sActivity = z4sEntities.activity.Where(
                    a => a.activity_id == activityId ).SingleOrDefault();

                if ( z4sActivity == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Activity", activityId.ToString() } );
                }
                return z4sActivity;
            }
        }

        /// <summary>
        /// Returns a sqlServerExecutionContext entity from a given sqlServerExecutionContext id
        /// </summary>
        /// <param name="sqlServerExecutionContextId">Unique identifier of a Zen4Sync sqlServerExecutionContext</param>
        /// <returns>A subscriber Entity</returns>
        public sqlServerExecutionContext GetSqlServerExecutionContext( Guid sqlServerExecutionContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlServerExecutionContext z4sSqlServerExecutionContext = z4sEntities.sqlServerExecutionContext.Include( "sqlServerExecutionParameter" ).Where(
                    s => s.sqlServerExecutionContext_id == sqlServerExecutionContextId ).SingleOrDefault();

                if ( z4sSqlServerExecutionContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "sqlServerExecutionContext", sqlServerExecutionContextId.ToString() } );
                }
                return z4sSqlServerExecutionContext;
            }
        }

        /// <summary>
        /// Returns a sqlServerCheckDataContext entity from a given sqlServerCheckDataContext id
        /// </summary>
        /// <param name="sqlServerCheckDataContextId">Unique identifier of a Zen4Sync sqlServerCheckDataContext</param>
        /// <returns>A subscriber Entity</returns>
        public sqlServerCheckDataContext GetSqlServerCheckDataContext( Guid sqlServerCheckDataContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlServerCheckDataContext z4sSqlServerCheckDataContext = z4sEntities.sqlServerCheckDataContext.Include( "sqlServerCheckDataParameter" ).Where(
                    s => s.sqlServerCheckDataContext_id == sqlServerCheckDataContextId ).SingleOrDefault();

                if ( z4sSqlServerCheckDataContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "sqlServerCheckDataContext", sqlServerCheckDataContextId.ToString() } );
                }
                return z4sSqlServerCheckDataContext;
            }
        }


        /// <summary>
        /// Returns a sqlceExecutionContext entity from a given sqlceExecutionContext id
        /// </summary>
        /// <param name="sqlceExecutionContextId">Unique identifier of a Zen4Sync sqlceExecutionContext</param>
        /// <returns>A subscriber Entity</returns>
        public sqlceExecutionContext GetSqlceExecutionContext( Guid sqlceExecutionContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlceExecutionContext z4sSqlceExecutionContext = z4sEntities.sqlceExecutionContext.Include( "sqlceExecutionParameter" ).Where(
                    s => s.sqlceExecutionContext_id == sqlceExecutionContextId ).SingleOrDefault();

                if ( z4sSqlceExecutionContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "sqlceExecutionContext", sqlceExecutionContextId.ToString() } );
                }
                return z4sSqlceExecutionContext;
            }
        }

        /// <summary>
        /// Returns a sqlceCheckDataContext entity from a given sqlceCheckDataContext id
        /// </summary>
        /// <param name="sqlceCheckDataContextId">Unique identifier of a Zen4Sync sqlceCheckDataContext</param>
        /// <returns>A subscriber Entity</returns>
        public sqlceCheckDataContext GetSqlceCheckDataContext( Guid sqlceCheckDataContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlceCheckDataContext z4sSqlceCheckDataContext = z4sEntities.sqlceCheckDataContext.Include( "sqlceCheckDataParameter" ).Where(
                    s => s.sqlceCheckDataContext_id == sqlceCheckDataContextId ).SingleOrDefault();

                if ( z4sSqlceCheckDataContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "sqlceCheckDataContext", sqlceCheckDataContextId.ToString() } );
                }
                return z4sSqlceCheckDataContext;
            }
        }

        /// <summary>
        /// Returns a sqlceCheckDataContext entity from a given sqlceCheckDataContext id
        /// </summary>
        /// <param name="sqlceCheckDataContextId">Unique identifier of a Zen4Sync sqlceCheckDataContext</param>
        /// <returns>A sqlceCheckDataContext Entity</returns>
        public sqlceBackupContext GetSqlceBackupContext( Guid sqlceBackupContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                sqlceBackupContext z4sSqlceBackupContext = z4sEntities.sqlceBackupContext.Where(
                    s => s.sqlceBackupContext_id == sqlceBackupContextId ).SingleOrDefault();

                if ( z4sSqlceBackupContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "sqlceBackupContext", sqlceBackupContextId.ToString() } );
                }
                return z4sSqlceBackupContext;
            }
        }

        /// <summary>
        /// Returns a mefExecutionContext entity from a given mefExecutionContext id
        /// </summary>
        /// <param name="mefExecutionContextId">Unique identifier of a Zen4Sync mefExecutionContext</param>
        /// <returns>A mefExecutionContext Entity</returns>
        public mefExecutionContext GetMefExecutionContext( Guid mefExecutionContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                mefExecutionContext z4sMefExecutionContext = z4sEntities.mefExecutionContext.Where(
                    m => m.mefExecutionContext_id == mefExecutionContextId ).SingleOrDefault();

                if ( z4sMefExecutionContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "mefExecutionContext", mefExecutionContextId.ToString() } );
                }
                return z4sMefExecutionContext;
            }
        }

        /// <summary>
        /// Returns a syncSessionContext entity from a given syncSessionContext id
        /// </summary>
        /// <param name="syncSessionContextId">Unique identifier of a Zen4Sync syncSessionContext</param>
        /// <returns>A syncSessionContext Entity</returns>
        public syncSessionContext GetSyncSessionContext( Guid syncSessionContextId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                syncSessionContext z4sSyncSessionContext = z4sEntities.syncSessionContext.Include( "subscriber" ).Where(
                    s => s.syncSessionContext_id == syncSessionContextId ).SingleOrDefault();

                if ( z4sSyncSessionContext == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "syncSessionContext", syncSessionContextId.ToString() } );
                }
                return z4sSyncSessionContext;
            }
        }

        /// <summary>
        /// Returns a testServer entity from a given testServer id
        /// </summary>
        /// <param name="testServerId">Unique identifier of the TestServer</param>
        /// <returns>A testServer entity from a given testServer id</returns>
        public testServer GetTestServer( Guid testServerId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                testServer z4sTestServer = z4sEntities.testServer.Where(
                    t => t.testServer_id == testServerId ).SingleOrDefault();

                if ( z4sTestServer == null )
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Test Server", testServerId.ToString() } );
                }
                return z4sTestServer;
            }
        }

        /// <summary>
        /// Returns all the clientSession entities of a testSession.
        /// </summary>
        /// <param name="testSessionId">Unique identifier of the Zen4Sync testSession.</param>
        /// <returns>All the clientSession entities of a testSession</returns>
        public List<clientSession> getClientSessions( Guid testSessionId )
        {
            using ( Zen4SyncRepositoryEntities z4sEntities = GetContext() )
            {
                List<clientSession> z4sClientSessions = z4sEntities.clientSession.Include( "testScenario" ).Include( "testScenario.activity" ).Include( "activityContext" ).Where(
                    c => c.clientSession_testSessionId == testSessionId ).ToList();
                return z4sClientSessions;
            }
        }

        /// <summary>
        /// Returns the path where the mef component is located
        /// </summary>
        /// <param name="mefExecutionId">Unique identifier of the Zen4Sync mefExecution</param>
        /// <returns>The path where the mef component is located</returns>
        public String GetMefDeploymentDirectory( Guid mefExecutionId )
        {
            mefExecution mefExe = GetMefExecution( mefExecutionId );
            using(Zen4SyncRepositoryEntities z4sEntities = GetContext())
            {
                mefDeployment z4sMefDeployment = z4sEntities.mefDeployment.Where(
                    m => m.mefDeployment_mefComponentVersionId == mefExe.mefExecution_mefComponentVersionId ).SingleOrDefault();

                if(z4sMefDeployment == null)
                {
                    throw new Zen4SyncModelException( Zen4SyncModelException.Messages.UNKNOWN_ITEM_BY_ID, new string[] { "Mef Deployment", mefExe.mefComponentVersion.mefComponentVersion_id.ToString() } );
                }
                return z4sMefDeployment.mefDeployment_mefDeploymentDirectory;
            }
        }

        //TODO: test
        /// <summary>
        /// Returns a byte table that containts the encrypted value of the data in the input.
        /// </summary>
        /// <param name="decryptedData">The data that should be encrypted</param>
        /// <param name="id">The unique identifier of the data</param>
        /// <param name="keyPassword">The password of the symmetric key</param>
        /// <returns>A byte table</returns>
       public Byte[] EncryptData( String decryptedData, Guid id, String keyPassword )
        {
            using(Zen4SyncRepositoryEntities context = GetContext())
            {

                ObjectParameter encryptedValue = new ObjectParameter( "encryptedValue", typeof( Byte[] ) );
                context.sp_z4s_encrypt_data( decryptedData, id, keyPassword, encryptedValue );

                if(encryptedValue.Value == null)
                    return null;

                return (Byte[]) (encryptedValue.Value);
            }
        }

        //TODO: test
       /// <summary>
       /// Returns a string that containts the decrypted value of the data in the input.
       /// </summary>
       /// <param name="decryptedData">The data that should be decrypted</param>
       /// <param name="id">The unique identifier of the data</param>
       /// <param name="keyPassword">The password of the symmetric key</param>
       /// <returns>The decrypted data</returns>
       public String DecryptData( Byte[] encryptedData, Guid id, String keyPassword )
       {
           using(Zen4SyncRepositoryEntities context = GetContext())
           {
               if(encryptedData == null)
                   return null;

               ObjectParameter decryptedValue = new ObjectParameter( "decryptedValue", typeof( String ) );
               context.sp_z4s_decrypt_data( encryptedData, id, keyPassword, decryptedValue );

               return (String)decryptedValue.Value;
           }

       }

    }
}
